module CU(
        input [5:0] Op,
        input [5:0] S,
        output reg PCWr,
        output reg PCWrCond,
        output reg IorD,
        output reg MemRd,
        output reg MemWr,
        output reg IRWr,
        output reg MemtoReg,
        output reg ALUSrcA,
        output reg RegWr,
        output reg RegDst,
        output reg [1:0] PCSrc,
        output reg [1:0] ALUOp,
        output reg [1:0] ALUSrcB,
        output reg [5:0] NS
    );

    // 定义操作码
`define J 6'b000010 //跳转
`define BEQ 6'b000100 //分支
`define R_TYPE 6'b000000 //寄存器操作
`define SW 6'b101011 //存储
`define LW 6'b100011 //加载
`define ADDIU 6'b001001
// `define SUBIU 6'b001011

    // 定义指令宏
`define FETCH 6'd0 //取指令
`define DECODE 6'd1 //指令译码
`define LOAD1_STORE1 6'd2 //地址计算
`define LOAD2 6'd3 //存储读
`define LOAD3 6'd4  //寄存器写
`define ALU1 6'd5 //存储写
`define STORE2 6'd6 //算逻运算
`define ALU2 6'd7 //寄存器写
`define BRANCH 6'd8 //分支转移
`define JUMP 6'd9 //跳转

`define ADDIU1 6'd10 //立即数加法
`define ADDIU2 6'd11 //立即数加法

    // 定义赋值函数
    always @(*) begin
        case (S)
            `FETCH: begin
                PCWr = 1;
                PCWrCond = 0;
                IorD = 0;
                MemRd = 1;
                MemWr = 0;
                IRWr = 1;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b01;
                ALUSrcA = 0;
                RegWr = 0;
                RegDst = 0;
                NS = `DECODE;
            end
            `DECODE: begin 
                PCWr = 0;
                PCWrCond = 0;
                IorD = 0;
                MemRd = 0;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b11;
                ALUSrcA = 0;
                RegWr = 0;
                RegDst = 0;
                case (Op) //XXX 指令扩展1
                    `J:
                        NS = `JUMP;
                    `BEQ:
                        NS = `BRANCH;
                    `R_TYPE:
                        NS = `ALU1;
                    `SW:
                        NS = `LOAD1_STORE1;
                    `LW:
                        NS = `LOAD1_STORE1;
                    `ADDIU:
                        NS = `ADDIU1;
                endcase
            end
            `LOAD1_STORE1: begin
                PCWr = 0;
                PCWrCond = 0;
                IorD = 0;
                MemRd = 0;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b10;
                ALUSrcA = 1;
                RegWr = 0;
                RegDst = 0;
                case (Op)
                    `LW:
                        NS = `LOAD2;
                    `SW:
                        NS = `STORE2;
                endcase
            end
            `LOAD2: begin
                PCWr = 0;
                PCWrCond = 0;
                IorD = 1;
                MemRd = 1;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b00;
                ALUSrcA = 0;
                RegWr = 0;
                RegDst = 0;
                NS = `LOAD3;
            end
            `LOAD3: begin
                PCWr = 0;
                PCWrCond = 0;
                IorD = 1;
                MemRd = 1;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 1;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b00;
                ALUSrcA = 0;
                RegWr = 1;
                RegDst = 0;
                NS = `FETCH;
            end
            `STORE2: begin
                PCWr = 0;
                PCWrCond = 0;
                IorD = 1;
                MemRd = 0;
                MemWr = 1;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b00;
                ALUSrcA = 0;
                RegWr = 0;
                RegDst = 0;
                NS = `FETCH;
            end
            `ALU1: begin
                PCWr = 0;
                PCWrCond = 0;
                IorD = 0;
                MemRd = 0;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b10;
                ALUSrcB = 2'b00;
                ALUSrcA = 1;
                RegWr = 0;
                RegDst = 0;
                NS = `ALU2;
            end
            `ALU2: begin
                PCWr = 0;
                PCWrCond = 0;
                IorD = 0;
                MemRd = 0;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b00;
                ALUSrcA = 0;
                RegWr = 1;
                RegDst = 1;
                NS = `FETCH;
            end
            `BRANCH: begin
                PCWr = 0;
                PCWrCond = 1;
                IorD = 0;
                MemRd = 0;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b01;
                ALUOp = 2'b01;
                ALUSrcB = 2'b00;
                ALUSrcA = 1;
                RegWr = 0;
                RegDst = 0;
                NS = `FETCH;
            end
            `JUMP: begin
                PCWr = 1;
                PCWrCond = 0;
                IorD = 0;
                MemRd = 0;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b10;
                ALUOp = 2'b00;
                ALUSrcB = 2'b00;
                ALUSrcA = 0;
                RegWr = 0;
                RegDst = 0;
                NS = `FETCH;
            end
            `ADDIU1: begin
                PCWr = 0;
                PCWrCond = 0;
                IorD = 0;
                MemRd = 0;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b10;
                ALUSrcA = 1;
                RegWr = 0;
                RegDst = 0;
                NS = `ADDIU2;
            end
            `ADDIU2: begin
                PCWr = 0;
                PCWrCond = 0;
                IorD = 0;
                MemRd = 0;
                MemWr = 0;
                IRWr = 0;
                MemtoReg = 0;
                PCSrc = 2'b00;
                ALUOp = 2'b00;
                ALUSrcB = 2'b00;
                ALUSrcA = 0;
                RegWr = 1;
                RegDst = 0;
                NS = `FETCH;
            end
        endcase
    end

endmodule
